import type { ComponentStyleIdType } from '../../types/interfaces'
import type { StepBarProps, StepItem, StepStatus } from './types'
import { UIComponent } from '../../lib/abstract'
import { ComponentStyleId, logger } from '../../types/constants'
import { styles } from './styles'
import { DEFAULT_STEP_PROPS, EDIT_STEP_STATUS, STEP_STATUS_ICONS } from './types'

export class StepBar extends UIComponent<StepBarProps> {
  id: string = 'step-bar'
  readonly description: string = '步骤条组件'
  readonly styleId: string = ComponentStyleId[this.name]
  private currentStepIndex: number = 0

  get name(): ComponentStyleIdType {
    return 'StepBar'
  }

  get className(): string {
    return 'custom-step-bar'
  }

  constructor(props: StepBarProps) {
    super({
      ...DEFAULT_STEP_PROPS,
      ...props,
    })

    // 注册样式
    this.registerStyles()
  }

  ELEMENT_SELECTORS = {
    stepItem: { selector: '.step-item', dynamic: true, unique: false },
  }

  render(): string {
    return `
      <div class="${this.className}">
        ${this.renderItem()}
      </div>
    `
  }

  renderItem() {
    const { steps } = this.props

    return `
      ${steps.map((step, index) => `
        <div class="step-item ${step.status || EDIT_STEP_STATUS.WAIT}" data-index="${index}">
          <div class="step-head">${this.getStepHeadContent(step, index)}</div>
          <div class="step-content">
            <div class="step-title">${step.title}</div>
            ${step.subTitle ? `<div class="step-subtitle">${step.subTitle}</div>` : ''}
          </div>
        </div>
      `).join('')}
    `
  }

  /**
   * 更新UI显示
   * @private
   */
  updateUI(): void {
    super.updateUI()

    const $container = $(this.selector)

    if ($container && $container.length) {
      // 更新组件内容
      $container?.html(this.renderItem())
      // 重新绑定事件
      this.bindEvents()
    }
  }

  /**
   * 更新步骤状态
   * @param index 步骤索引
   * @param status 新状态
   */
  updateStepStatus(index: number, status: StepStatus): void {
    if (index < 0 || index >= this.props.steps.length) {
      logger.warn(`[${this.name}] 无效的步骤索引: ${index}`)
      return
    }

    // 不能更新未到的步骤
    if (this.currentStepIndex < index) {
      return
    }

    const step = this.props.steps[index]
    const currentStatus: StepStatus = step.status ?? EDIT_STEP_STATUS.WAIT

    // 更新状态
    step.status = status
    logger.info(`[${this.name}] 更新'${step.title}'步骤状态`, {
      index,
      from: currentStatus,
      to: status,
    })

    this.updateUI()
  }

  /**
   * 设置当前步骤
   * @param current 当前步骤索引
   */
  setCurrentStep(current: number): void {
    if (current < 0 || current >= this.props.steps.length) {
      logger.warn(`[${this.name}] 无效的当前步骤索引: ${current}`)
      return
    }

    this.currentStepIndex = current

    this.props.current = current
    this.updateStepsStatus()
    this.updateUI()
  }

  /**
   * 更新所有步骤状态
   */
  private updateStepsStatus(): void {
    const haseError = this.props.steps.some(step => step.status === EDIT_STEP_STATUS.ERROR)

    this.props.steps.forEach((step, index) => {
      if (index < this.props.current!) {
        step.status = EDIT_STEP_STATUS.FINISH
      }
      else if (index === this.props.current!) {
        step.status = EDIT_STEP_STATUS.PROCESS
        if (index === this.props.steps.length - 1) {
          step.status = haseError ? EDIT_STEP_STATUS.ERROR : EDIT_STEP_STATUS.FINISH
        }
      }
      else {
        step.status = EDIT_STEP_STATUS.WAIT
      }
    })
  }

  /**
   * 获取步骤头内容
   * @param step 步骤项
   * @param index 步骤索引
   */
  private getStepHeadContent(step: StepItem, index: number): string {
    if (step.icon)
      return step.icon

    const status = step.status || EDIT_STEP_STATUS.WAIT
    const icons: Record<StepStatus, string> = {
      ...STEP_STATUS_ICONS,
      wait: (index + 1).toString(),
      process: (index + 1).toString(),
    }

    return icons[status] || (index + 1).toString()
  }

  bindEvents(): void {
    if (!this.props.onChange)
      return

    this.getElement('stepItem')?.on('click', (e) => {
      const datIndex = $(e.currentTarget).data('index') as string
      const index = Number.parseInt(datIndex, 10)
      this.props.onChange?.(index)
    })
  }

  getStyles(): string {
    return styles(this.className, { direction: this.props.direction })
  }

  destroy(): void {
    super.destroy()
  }
}
